#include <string.h>
#include <stdio.h>
#include "symtable.h"

#define STRMAX 999 // size of lexemes array
#define SYMMAX 100 // size of symtable

char lexemes[STRMAX];
int lastchar = -1; // last used position in lexemes
struct entry symtable[SYMMAX];
int lastentry = 0; //last used position in symtable
const int OUT_OF_SCOPE = -1;

/* find a specific symbol in the symbol table
 * as long as its not out of scope
 * this is to be used when looking if a symbol is visible
 * probably to use it somewhere
 *
 * returns:
 ** symbol index: symbol exists
 ** 0: no symbol is found
 */
int lookup(char s[]) {
	int p;
	for (p = lastentry; p> 0; p--) {
		// Found entry if they have the same name and has any scope
		if (strcmp(symtable[p].lexptr, s) == 0 && symtable[p].scope != OUT_OF_SCOPE) {
			return p;
		}
	}
	return 0;
}

/* find a specific symbol in the symbol table
 * in the current scope
 * this should be used when initialising symbols, to make sure a symbol
 * doesn't exist with the same name in the same scope (it can replace older scopes)
 *
 * returns:
 ** symbol index: symbol found
 ** 0: no symbol is found
 */
int lookup_scope(char s[]) {
	int p;
	for (p = lastentry; p> 0; p--) {
		// Found entry if they have the same name and same scope
		if (strcmp(symtable[p].lexptr, s) == 0 && symtable[p].scope == scope) {
			return p;
		}
	}
	return 0;
}

/* insert entry in symbol table
 * if symbol is already in table, return its index
 *
 * returns:
 ** symbol index: succesfully inserted (or was already there)
 ** 0: insertion failed
 */
int insert(char s[], int tok) {

	// Symbol exists with the exact same name and scope, return its index
	int index = lookup(s);
	if (index) {
		return index;
	}

	// Not enough room in symbol table
	int len;
	len = strlen(s);
	if (lastentry +1 >= SYMMAX) {
		printf("symbol table full");
		return 0;
	}

	if (lastchar +len +1 >= STRMAX) {
		printf("lexemes array full");
		return 0;
	}

	lastentry = lastentry +1;
	symtable[lastentry].token = tok;
	symtable[lastentry].lexptr = &lexemes[lastchar +1];
	symtable[lastentry].scope = scope;
	lastchar = lastchar +len +1;
	strcpy(symtable[lastentry].lexptr, s);
	return lastentry;
}

int insert_data(char s[], int tok, int data) {
	int index = insert(s, tok);
	symtable[index].data = data;
}

void increase_scope() { scope++; }
void decrease_scope() {

	// Mark all variables with current scope as out of scope
	for (int i = 0; i <= lastentry; i++) {
		if (symtable[i].scope == scope) {
			symtable[i].scope = OUT_OF_SCOPE;
		}
	}

	// Decrease scope
	scope--;
}

// struct

char struct_lexemes[STRMAX];
int struct_lastchar = -1; // last used position in lexemes
struct struct_entry struct_symtable[SYMMAX];
int struct_lastentry = 0; //last used position in symtable

int struct_lookup(char s[]) {
	int p;
	for (p = struct_lastentry; p > 0; p--) {
		if (strcmp(struct_symtable[p].lexptr, s) == 0) {
			return p;
		}
	}
	return 0;
}

int struct_insert(char s[], struct entry *st) {

	int index = struct_lookup(s);
	if (index) {
		return index;
	}

	int len;
	len = strlen(s);
	if (struct_lastentry +1 >= SYMMAX) {
		printf("struct symbol table full");
		return 0;
	}

	if (struct_lastchar +len +1 >= STRMAX) {
		printf("struct lexemes array full");
		return 0;
	}

	struct_lastentry = struct_lastentry +1;
	struct_symtable[struct_lastentry].st = st;
	struct_symtable[struct_lastentry].lexptr = &struct_lexemes[struct_lastchar +1];
	struct_lastchar = struct_lastchar +len +1;
	strcpy(struct_symtable[struct_lastentry].lexptr, s);
	return struct_lastentry;

}
